defmodule SockWorkstation.PingPongGen do
  use GenServer

  alias SockWorkstation.{SockCoopClient, CoopMgrGen, ASRHelperGen}
  @name __MODULE__

  def start_link(_init_arg) do
    GenServer.start_link(@name, [], name: @name)
    # GenServer.start_link(@name, session_id, name: via_tuple(session_id, "pingpong_helper"))
  end

  @impl true
  def init(_initial_value) do
    self_pid = self()

    IO.puts("PingPongGen started")

    state =
      %{
        self_pid: self_pid,
        # session_id: session_id,
        coop_pid: nil,
        # inter_peer: nil
        # sent_list: []
      }

    {:ok, state}
  end

  def get_state() do
    GenServer.call(@name, :get_state)
    # GenServer.call(via_tuple(session_id, "pingpong_helper"), :get_state)
  end

  # def fetch_coop_pid(session_id, pid) do
  #   GenServer.cast(via_tuple(session_id, "pingpong_helper"), {:fetch_coop_pid, pid})
  # end

  def start_intercom(fr_sessid, to_sessid) do
    GenServer.cast(
      @name,
      {:start_intercom, {fr_sessid, to_sessid}}
    )
  end

  def stop_intercom(fr_sessid, to_sessid) do
    GenServer.cast(
      @name,
      {:stop_intercom, {fr_sessid, to_sessid}}
    )
  end

  def switch_totalk(fr_sessid) do
    GenServer.cast(@name, {:switch_totalk, fr_sessid})
  end

  def switch_frtalk(fr_sessid) do
    GenServer.cast(@name, {:switch_frtalk, fr_sessid})
  end

  # def prep_intercom(session_id, fr_sessid, to_sessid) do
  #   GenServer.cast(
  #     via_tuple(session_id, "pingpong_helper"),
  #     {:prep_intercom, fr_sessid, to_sessid}
  #   )
  # end

  @impl true
  def handle_call(:get_state, _from, state) do
    {:reply, {:ok, state}, state}
  end

  # def switch_totalk(fr_sessid, to_sessid) do
  #   GenServer.cast(@name, {:switch_totalk, fr_sessid, to_sessid})
  # end

  @impl true
  #   def handle_cast({:fetch_coop_pid, coop_pid}, state) when coop_pid == state.coop_pid do
  #   {:noreply, state}
  # end

  # def handle_cast({:fetch_coop_pid, coop_pid}, state) do
  #   {:noreply, %{state | coop_pid: coop_pid}}
  # end

  def handle_cast({:start_intercom, {fr_sessid, to_sessid}}, state) do
    with {:ok, coop_pid} <- CoopMgrGen.prep_intercom(fr_sessid, fr_sessid, to_sessid) do
      # CoopMgrGen.toggle_speaking(fr_sessid)
      # CoopMgrGen.toggle_speaking(to_sessid)
      SockCoopClient.send_start_intercom(coop_pid, fr_sessid, to_sessid)
      # CoopMgrGen.toggle_autolisten(to_sessid)
      # CoopMgrGen.toggle_autolisten(fr_sessid)
      Process.send_after(state.self_pid, {:switch_frtalk, fr_sessid}, 250)
      # send(state.tts_helper_pid, {:inter_com, {fr_sessid, to_sessid}})
      state =
        state
        |> Map.put(:coop_pid, coop_pid)
        |> Map.put(fr_sessid, to_sessid)

      {:noreply, state}
    end
  end

  def handle_cast({:stop_intercom, {fr_sessid, to_sessid}}, state) do
    with {:ok, coop_pid} <- CoopMgrGen.unprep_intercom(fr_sessid, fr_sessid, to_sessid) do
      SockCoopClient.send_stop_intercom(coop_pid, fr_sessid, to_sessid)
      ASRHelperGen.toggle_asr(to_sessid)
      ASRHelperGen.toggle_asr(fr_sessid)
      # CoopMgrGen.toggle_not_autolisten(to_sessid)
      # CoopMgrGen.toggle_not_autolisten(fr_sessid)

      # send(state.tts_helper_pid, :inter_com)
      state =
        state
        |> Map.delete(fr_sessid)
        |> Map.delete(to_sessid)

      {:noreply, state}
    end
  end

  # def handle_cast({:stop_intercom, {fr_sessid, to_sessid}}, state) do
  #   # SockCoopClient.send_stop_intercom(state.coop_pid, fr_sessid, to_sessid)
  #   # send(state.tts_helper_pid, :inter_com)
  #   state =
  #     state
  #     |> Map.delete(fr_sessid)
  #     |> Map.delete(to_sessid)

  #   {:noreply, state}
  # end

  # def handle_cast({:prep_intercom, fr_sessid, to_sessid}, state) do
  #   CoopMgrGen.toggle_speaking(fr_sessid)
  #   CoopMgrGen.toggle_speaking(to_sessid)
  #   IO.puts("Prepare intercom #{fr_sessid} to #{to_sessid}")

  #   state =
  #     state
  #     |> Map.put(:inter_peer, {fr_sessid, to_sessid})

  #   {:noreply, state}
  # end

  def handle_cast({:switch_totalk, fr_sessid}, state) do
    cond do
      state[fr_sessid] == nil ->
        IO.puts("No intercom")
        {:noreply, state}

      true ->
        to_sessid = state[fr_sessid]
        CoopMgrGen.toggle_speaking(fr_sessid)
        Process.sleep(120)
        CoopMgrGen.toggle_listening(to_sessid)
        ASRHelperGen.toggle_vad(to_sessid)
        Process.sleep(150)
        # CoopMgrGen.start_listened(to_sessid)

        IO.puts("Switch talk #{fr_sessid} to #{to_sessid}")

        state =
          state
          |> Map.delete(fr_sessid)
          |> Map.put(to_sessid, fr_sessid)

        {:noreply, state}
    end
  end

  def handle_cast({:switch_frtalk, fr_sessid}, state) do
    cond do
      state[fr_sessid] == nil ->
        IO.puts("No intercom")
        {:noreply, state}

      true ->
        to_sessid = state[fr_sessid]
        # CoopMgrGen.toggle_speaking(to_sessid)
        # Process.sleep(120)
        CoopMgrGen.toggle_listening(fr_sessid)
        ASRHelperGen.toggle_vad(fr_sessid)
        Process.sleep(150)
        # CoopMgrGen.start_listened(fr_sessid)
        # Process.sleep(150)

        IO.puts("Switch talk #{fr_sessid} to #{to_sessid}")

        state =
          state
          |> Map.put(fr_sessid, to_sessid)

        {:noreply, state}
    end
  end
  # defp via_tuple(session_id, type) do
  #   {:via, Registry, {SockWorkstation.SessionRegistry, {session_id, type}}}
  # end

  # def handle_cast({:lstn_to_pid, sessid, to_pid}, state) do
  #   state =
  #     state
  #     |> Map.put(sessid, to_pid)

  #   {:noreply, state}
  # end

  # def handle_info(:lstn, state) do
  #   # IO.puts("Received lstn bin: #{inspect(byte_size(data))}")
  #   {:noreply, state}
  # end
  @impl true

  def handle_info({:switch_frtalk, fr_sessid}, state) do
    cond do
      state[fr_sessid] == nil ->
        IO.puts("No intercom")
        {:noreply, state}

      true ->
        to_sessid = state[fr_sessid]
        # CoopMgrGen.toggle_speaking(to_sessid)
        # Process.sleep(120)
        CoopMgrGen.toggle_listening(fr_sessid)
        ASRHelperGen.toggle_vad(fr_sessid)
        Process.sleep(150)
        # CoopMgrGen.start_listened(fr_sessid)

        IO.puts("Switch talk #{fr_sessid} to #{to_sessid}")

        state =
          state
          |> Map.put(fr_sessid, to_sessid)

        {:noreply, state}
    end
  end
end
